Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
42.86% |
3 / 7 |
CRAP | |
88.07% |
96 / 109 |
| ProjectController | |
0.00% |
0 / 1 |
|
42.86% |
3 / 7 |
24.98 | |
88.07% |
96 / 109 |
| __construct | |
100.00% |
1 / 1 |
1 | |
100.00% |
16 / 16 |
|||
| createAction | |
0.00% |
0 / 1 |
7.54 | |
77.78% |
21 / 27 |
|||
| removeAction | |
0.00% |
0 / 1 |
4.37 | |
71.43% |
5 / 7 |
|||
| searchAction | |
100.00% |
1 / 1 |
3 | |
100.00% |
19 / 19 |
|||
| getAction | |
100.00% |
1 / 1 |
1 | |
100.00% |
8 / 8 |
|||
| searchContributorsAction | |
0.00% |
0 / 1 |
2.00 | |
90.91% |
10 / 11 |
|||
| showAction | |
0.00% |
0 / 1 |
6.25 | |
80.95% |
17 / 21 |
|||
| <?php | |
| /* | |
| * This file is part of the Akeneo PIM Enterprise Edition. | |
| * | |
| * (c) 2016 Akeneo SAS (http://www.akeneo.com) | |
| * | |
| * For the full copyright and license information, please view the LICENSE | |
| * file that was distributed with this source code. | |
| */ | |
| namespace Akeneo\Pim\WorkOrganization\TeamworkAssistant\Bundle\Controller; | |
| use Akeneo\Pim\WorkOrganization\TeamworkAssistant\Bundle\Datagrid\Filter\ProjectCompletenessFilter; | |
| use Akeneo\Pim\WorkOrganization\TeamworkAssistant\Bundle\Datagrid\FilterConverter; | |
| use Akeneo\Pim\WorkOrganization\TeamworkAssistant\Bundle\Job\ProjectCalculationJobLauncher; | |
| use Akeneo\Pim\WorkOrganization\TeamworkAssistant\Bundle\Security\ProjectVoter; | |
| use Akeneo\Pim\WorkOrganization\TeamworkAssistant\Component\Factory\ProjectFactoryInterface; | |
| use Akeneo\Pim\WorkOrganization\TeamworkAssistant\Component\Repository\ProjectCompletenessRepositoryInterface; | |
| use Akeneo\Pim\WorkOrganization\TeamworkAssistant\Component\Repository\ProjectRepositoryInterface; | |
| use Akeneo\Tool\Component\StorageUtils\Remover\RemoverInterface; | |
| use Akeneo\Tool\Component\StorageUtils\Repository\SearchableRepositoryInterface; | |
| use Akeneo\Tool\Component\StorageUtils\Saver\SaverInterface; | |
| use Akeneo\Tool\Component\StorageUtils\Updater\ObjectUpdaterInterface; | |
| use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; | |
| use Symfony\Component\HttpFoundation\JsonResponse; | |
| use Symfony\Component\HttpFoundation\RedirectResponse; | |
| use Symfony\Component\HttpFoundation\Request; | |
| use Symfony\Component\HttpFoundation\Response; | |
| use Symfony\Component\Routing\RouterInterface; | |
| use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; | |
| use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; | |
| use Symfony\Component\Serializer\Normalizer\NormalizerInterface; | |
| use Symfony\Component\Validator\Validator\ValidatorInterface; | |
| /** | |
| * Project controller. | |
| * | |
| * @author Willy Mesnage <willy.mesnage@akeneo.com> | |
| */ | |
| class ProjectController | |
| { | |
| /** @var FilterConverter */ | |
| protected $filterConverter; | |
| /** @var ValidatorInterface */ | |
| protected $validator; | |
| /** @var ProjectFactoryInterface */ | |
| protected $projectFactory; | |
| /** @var SaverInterface */ | |
| protected $projectSaver; | |
| /** @var ObjectUpdaterInterface */ | |
| protected $projectUpdater; | |
| /** @var RemoverInterface */ | |
| protected $projectRemover; | |
| /** @var ProjectCalculationJobLauncher*/ | |
| protected $projectCalculationJobLauncher; | |
| /** @var NormalizerInterface */ | |
| protected $projectNormalizer; | |
| /** @var ProjectRepositoryInterface */ | |
| protected $projectRepository; | |
| /** @var SearchableRepositoryInterface */ | |
| protected $userRepository; | |
| /** @var TokenStorageInterface */ | |
| protected $tokenStorage; | |
| /** @var ProjectCompletenessRepositoryInterface */ | |
| protected $projectCompletenessRepository; | |
| /** @var AuthorizationCheckerInterface */ | |
| protected $authorizationChecker; | |
| /** @var RouterInterface */ | |
| protected $router; | |
| /** @var NormalizerInterface */ | |
| protected $projectCompletenessNormalizer; | |
| /** | |
| * @param FilterConverter $filterConverter | |
| * @param ProjectFactoryInterface $projectFactory | |
| * @param SaverInterface $projectSaver | |
| * @param ObjectUpdaterInterface $projectUpdater | |
| * @param RemoverInterface $projectRemover | |
| * @param ValidatorInterface $validator | |
| * @param ProjectCalculationJobLauncher $projectCalculationJobLauncher | |
| * @param NormalizerInterface $projectNormalizer | |
| * @param ProjectRepositoryInterface $projectRepository | |
| * @param SearchableRepositoryInterface $userRepository | |
| * @param TokenStorageInterface $tokenStorage | |
| * @param ProjectCompletenessRepositoryInterface $projectCompletenessRepository | |
| * @param AuthorizationCheckerInterface $authorizationChecker | |
| * @param RouterInterface $router | |
| * @param NormalizerInterface $projectCompletenessNormalizer | |
| */ | |
| public function __construct( | |
| FilterConverter $filterConverter, | |
| ProjectFactoryInterface $projectFactory, | |
| SaverInterface $projectSaver, | |
| ObjectUpdaterInterface $projectUpdater, | |
| RemoverInterface $projectRemover, | |
| ValidatorInterface $validator, | |
| ProjectCalculationJobLauncher $projectCalculationJobLauncher, | |
| NormalizerInterface $projectNormalizer, | |
| ProjectRepositoryInterface $projectRepository, | |
| SearchableRepositoryInterface $userRepository, | |
| TokenStorageInterface $tokenStorage, | |
| ProjectCompletenessRepositoryInterface $projectCompletenessRepository, | |
| AuthorizationCheckerInterface $authorizationChecker, | |
| RouterInterface $router, | |
| NormalizerInterface $projectCompletenessNormalizer | |
| ) { | |
| $this->filterConverter = $filterConverter; | |
| $this->projectFactory = $projectFactory; | |
| $this->validator = $validator; | |
| $this->projectSaver = $projectSaver; | |
| $this->projectUpdater = $projectUpdater; | |
| $this->projectCalculationJobLauncher = $projectCalculationJobLauncher; | |
| $this->projectNormalizer = $projectNormalizer; | |
| $this->projectRepository = $projectRepository; | |
| $this->userRepository = $userRepository; | |
| $this->tokenStorage = $tokenStorage; | |
| $this->projectCompletenessRepository = $projectCompletenessRepository; | |
| $this->authorizationChecker = $authorizationChecker; | |
| $this->router = $router; | |
| $this->projectCompletenessNormalizer = $projectCompletenessNormalizer; | |
| $this->projectRemover = $projectRemover; | |
| } | |
| /** | |
| * @param Request $request | |
| * | |
| * @return Response | |
| */ | |
| public function createAction(Request $request) | |
| { | |
| if (!$request->isXmlHttpRequest()) { | |
| return new RedirectResponse('/'); | |
| } | |
| $datagridViewFilters = []; | |
| $projectData = $request->request->get('project'); | |
| $user = $this->tokenStorage->getToken()->getUser(); | |
| parse_str($projectData['datagrid_view']['filters'], $datagridViewFilters); | |
| if (isset($projectData['code'])) { | |
| $project = $this->projectRepository->findOneByIdentifier($projectData['code']); | |
| if (null === $project || !$this->authorizationChecker->isGranted([ProjectVoter::OWN], $project)) { | |
| return new JsonResponse(sprintf('No project with code "%s"', $projectData['code']), 400); | |
| } | |
| $projectData = array_intersect_key($projectData, array_flip(['label', 'due_date', 'description'])); | |
| $this->projectUpdater->update($project, $projectData); | |
| } else { | |
| $projectData['owner'] = $user->getUsername(); | |
| $projectData['product_filters'] = $this->filterConverter->convert($datagridViewFilters['f']); | |
| $project = $this->projectFactory->create($projectData); | |
| } | |
| $violations = $this->validator->validate($project); | |
| if (0 === $violations->count()) { | |
| $this->projectSaver->save($project); | |
| $this->projectCalculationJobLauncher->launch($project); | |
| $normalizedProject = $this->projectNormalizer->normalize($project, 'internal_api'); | |
| return new JsonResponse($normalizedProject, 201); | |
| } | |
| $errors = []; | |
| foreach ($violations as $violation) { | |
| $errors[] = [ | |
| 'field' => $violation->getPropertyPath(), | |
| 'message' => $violation->getMessage(), | |
| ]; | |
| } | |
| return new JsonResponse($errors, 400); | |
| } | |
| /** | |
| * @param Request $request | |
| * @param string $identifier | |
| * | |
| * @return Response | |
| */ | |
| public function removeAction(Request $request, $identifier) | |
| { | |
| if (!$request->isXmlHttpRequest()) { | |
| return new RedirectResponse('/'); | |
| } | |
| $project = $this->projectRepository->findOneByIdentifier($identifier); | |
| if (null === $project || !$this->authorizationChecker->isGranted([ProjectVoter::OWN], $project)) { | |
| return new JsonResponse(sprintf('No project with code "%s"', $identifier), 400); | |
| } | |
| $this->projectRemover->remove($project); | |
| return new JsonResponse(null, 204); | |
| } | |
| /** | |
| * Returns Projects in terms of search and options. | |
| * Options accept 'limit' => (int) and 'page' => (int) and 'user' => UserInterface. | |
| * | |
| * @param Request $request | |
| * | |
| * @return JsonResponse | |
| */ | |
| public function searchAction(Request $request) | |
| { | |
| $options = ['limit' => 20, 'page' => 1, 'completeness' => '1']; | |
| $options = array_merge($options, $request->query->get('options', [])); | |
| $contributor = $this->tokenStorage->getToken()->getUser()->getUsername(); | |
| $computeCompleteness = boolval($options['completeness']); | |
| $projects = $this->projectRepository->findBySearch( | |
| $request->query->get('search'), | |
| [ | |
| 'limit' => $options['limit'], | |
| 'page' => $options['page'], | |
| 'user' => $this->tokenStorage->getToken()->getUser(), | |
| ] | |
| ); | |
| $normalizedProjects = []; | |
| foreach ($projects as $project) { | |
| $normalizedProject = $this->projectNormalizer->normalize($project, 'internal_api'); | |
| /* For scalability reasons, the completeness is not attached to the normalizer. Indeed, the computing of a | |
| * completeness can be very time consuming. */ | |
| if ($computeCompleteness) { | |
| $normalizedProject['completeness'] = $this->projectCompletenessNormalizer->normalize( | |
| $this->projectCompletenessRepository->getProjectCompleteness( | |
| $project, | |
| $contributor | |
| ), | |
| 'internal_api' | |
| ); | |
| } | |
| $normalizedProjects[] = $normalizedProject; | |
| } | |
| return new JsonResponse($normalizedProjects, 200); | |
| } | |
| /** | |
| * @param string $identifier | |
| * | |
| * @return JsonResponse | |
| */ | |
| public function getAction($identifier) | |
| { | |
| $contributor = $this->tokenStorage->getToken()->getUser()->getUsername(); | |
| $project = $this->projectRepository->findOneByIdentifier($identifier); | |
| $normalizedProject = $this->projectNormalizer->normalize($project, 'internal_api'); | |
| /* For scalability reasons, the completeness is not attached to the normalizer. Indeed, the computing of a | |
| * completeness can be very time consuming. */ | |
| $normalizedProject['completeness'] = $this->projectCompletenessNormalizer->normalize( | |
| $this->projectCompletenessRepository->getProjectCompleteness( | |
| $project, | |
| $contributor | |
| ), | |
| 'internal_api' | |
| ); | |
| return new JsonResponse($normalizedProject, 200); | |
| } | |
| /** | |
| * Returns users that belong to the project. | |
| * | |
| * @param Request $request | |
| * @param string $identifier | |
| * | |
| * @return JsonResponse | |
| */ | |
| public function searchContributorsAction($identifier, Request $request) | |
| { | |
| $project = $this->projectRepository->findOneByIdentifier($identifier); | |
| if (null === $project) { | |
| return new JsonResponse(null, 404); | |
| } | |
| $options = $request->query->get('options', ['limit' => 20, 'page' => 1]); | |
| $users = $this->userRepository->findBySearch( | |
| $request->query->get('search'), | |
| [ | |
| 'limit' => $options['limit'], | |
| 'page' => $options['page'], | |
| 'project' => $project, | |
| ] | |
| ); | |
| $normalizedProjects = $this->projectNormalizer->normalize($users, 'internal_api'); | |
| return new JsonResponse($normalizedProjects, 200); | |
| } | |
| /** | |
| * The "show" action of a project means redirecting the user on the datagrid filtered with the Project's view. | |
| * If a "status" is specified, we fill in the project completeness filter depending on the user permissions. | |
| * | |
| * @param string $identifier | |
| * @param string $status | |
| * | |
| * @Template("AkeneoPimTeamworkAssistantBundle:Project:filter-grid.html.twig") | |
| * | |
| * @return array|RedirectResponse|JsonResponse | |
| */ | |
| public function showAction($identifier, $status) | |
| { | |
| $project = $this->projectRepository->findOneByIdentifier($identifier); | |
| if (null === $project || | |
| !$this->authorizationChecker->isGranted([ProjectVoter::OWN, ProjectVoter::CONTRIBUTE], $project) | |
| ) { | |
| return new JsonResponse([ | |
| 'route' => 'pim_enrich_product_index' | |
| ]); | |
| } | |
| $ownerStatuses = [ | |
| 'owner-todo' => ProjectCompletenessFilter::OWNER_TODO, | |
| 'owner-inprogress' => ProjectCompletenessFilter::OWNER_IN_PROGRESS, | |
| 'owner-done' => ProjectCompletenessFilter::OWNER_DONE, | |
| ]; | |
| $contributorStatuses = [ | |
| 'contributor-todo' => ProjectCompletenessFilter::CONTRIBUTOR_TODO, | |
| 'contributor-inprogress' => ProjectCompletenessFilter::CONTRIBUTOR_IN_PROGRESS, | |
| 'contributor-done' => ProjectCompletenessFilter::CONTRIBUTOR_DONE | |
| ]; | |
| $statusCode = 0; | |
| if (array_key_exists($status, $ownerStatuses)) { | |
| if (!$this->authorizationChecker->isGranted([ProjectVoter::OWN], $project)) { | |
| return new JsonResponse([ | |
| 'route' => 'pim_enrich_product_index' | |
| ]); | |
| } | |
| $statusCode = $ownerStatuses[$status]; | |
| } elseif (array_key_exists($status, $contributorStatuses)) { | |
| $statusCode = $contributorStatuses[$status]; | |
| } | |
| return [ | |
| 'view' => $project->getDatagridView(), | |
| 'status' => $statusCode | |
| ]; | |
| } | |
| } |